
Arcade Game Designer
Copyright 2009 Jonathan Cauldwell.

This document is probably best viewed in a monospaced font.



Instructions for version 2.0
----------------------------

Like PGD and SEUD, Arcade Game Designer is a tool for writing your own simple arcade games.  While it isn't as easy to use as those 2 utilities and won't help you create snazzy shoot-em-ups or platform games, it should be capable of producing a variety of basic arcade affairs, as long as you're patient and prepared to stick at it.  That is, of course, provided that PGD does not crash horribly or something.  Games produced using the utility are stand-alone and can be distributed freely.

Now for the bad news.  AGD has its own built-in language, a rather simplistic affair with simple functions and a few built-in variables which you'll have to pick up.  In truth the lexicon is quite small, it's mostly a question of understanding how to use each particular command or function.  While the program will tell you if it finds a word it doesn't understand (although it won't say where), syntax checking is non-existent.  Unlike PGD and SEUD, AGD is decidedly user-unfriendly.

Because I wanted to produce a games designer for everyone to use, the program is free to download from my website.  Copyright, however, remains with the author.  Donations are not wanted, so if you really must show your appreciation go out and buy a copy of SEUD or PGD from www.cronosoft.co.uk or something.

AGD comes as you find it, cobbled together in a few weeks and very probably riddled with bugs I haven't found and for which I do not have the time to test.  As such, please do not expect email support - I will be happy to answer questions and hear requests for enhancements on the WoS forums instead.  I may get around to an update at some point in the future, other projects premitting.  Until then save your work as often as possible, and preferably as a snapshot if you are using an emulator.

Most importantly of all, have fun.  In the meantime, I'm off to Ripley to get hideously drunk.


Jonathan Cauldwell, 4th April 2008.

http://jonathan6.fortunecity.com/egghead/


Release history

0.3  04.04.2008 - first public release
0.4  05.04.2008 - corrected memory management bug which caused many knock-on problems
                - fixed a problem with the sound compilation
                - added code to display message number in the message editor
0.5  06.04.2008 - fixed bug moving to next level
                - fixed bug whereby only 6 sprites appeared on screen, instead of maximum 12
0.6  12.04.2008 - added functionality for ADD and SUBTRACT
                - added events for restart and initialise sprite
                - games are now saved properly, so should now be entirely stand-alone
                - fixed bug in scoring routine
0.7  13.04.2008 - fixed anti-flicker sprite sort
                - fixed delete message bug
                - removed debug code which prevented saved games being reloaded
0.8  18.04.2008 - added map layout code
                - added DISPLAY command to display numeric values
                - code editor now makes use of as much RAM as possible
                - now returns address of score string to BASIC
0.9  27.04.2008 - window resize now shows character squares in a chessboard pattern
                - fixed lock up caused by delete block routine
1.0  29.04.2008 - should be fairly stable now, so we'll call this version 1.0  ;)
                - added new deadly block, and new DEADLY collision test
                - replaced missing code for sprite copy and paste
                - fixed a bug in the sprite initialisation event
1.1  07.05.2008 - fixed bug in SPAWN routine
                - added WAITKEY command
1.3  28.02.2009 - rewrote sprite routines to eliminate flicker
                - added JUMP and FALL commands
                - added jump table editor
1.4  01.03.2009 - added global variables E, F, G and H
                - SCORE, BORDER, COLOUR, DELAY, MESSAGE now accept variables as arguments
1.5  02.05.2009 - added object editor to main menu
                - added GOT, GET, PUT, DETECTOBJ
                - added global variables I, J, K and L, plus object handling variable OBJ
                - fixed screen corruption in text editor
2.0  29.08.2009 - screen data is now stored in a compressed format
                - changing screens with LET SCREEN = now changes the map position
                - added TOGGLE command
                - increased speed of sprite routine
                - fixed bugs which occurred when deleting screens or resizing window





Constructing a game
-------------------

Basically, games are a combination of different elements:
* character blocks are combined together to form screens
* sprites (including the player) are positioned in their starting positions on each screen, and assigned a type characteristic
* logic is then written for each type of sprite - player, enemies, objects etc.

After that, it's a question of adding anything else you want.




Main Menu
---------

Enables you to select a function of the game you wish to design.  The amount of memory remaining available to your application is displayed in the top right corner of the this screen.




Window area
-----------

You can vary the play area's size and position in the Window/scrolling option.  The cursor keys allow you to position the window anywhere on screen.

Changing the window size and/or scrolling direction can alter the amount of data required for each column or row of blocks in each screen, and thus invalidate the present levels.  If this is the case, the program will ask if you wish to destroy the map data before allowing you to proceed.  It is a good idea to select the size of the play area first, and stick with it.

1 - narrow window
2 - widen window
Q - shorten window
A - lengthen window



Keys
----

This allows you to define the keys your game will use.  7 Keys are permitted.



Character Block Design
----------------------

Blocks are used to construct the screens.  Each block is 8 x 8 pixels in size, and has a different type assigned to it.  There are a number of different types, each with its own different set of attributes.  These are:

EMPTY SPACE     - player can move freely through free space blocks.
NORMAL PLATFORM - player may move freely past platforms from left, right or below.
SOLID WALL      - a block which is impassable from any direction.
LADDER          - player may move freely through ladder blocks in any direction.
FODDER          - treated as solid wall, but these can be removed with certain functions.
DEADLY          - sprites move through this, DEADLY function tests for contact


Move cursor around the character with the cursor keys.  Use SPACE or 0 to set/unset a pixel.  ENTER returns to the main menu.

Q = Move left through list of block properties
W = Move right through list of block properties
L = Last block
N = Next block
P = Paper colour
I = Ink colour
B = Toggle brightness
M = Copy current block to clipboard
K = Paste block from clipboard
C = Clear current block
X = Create a new character block
D = Delete current character block
ENTER = Return to main menu



Screen Layout
-------------

Move cursor around the screen with cursor keys.  Use 1 and 2 to select the character block you wish to place at the current cursor position.  SPACE or 0 places the desired block on the current screen at this position.  ENTER returns to the main menu.

1 = Move left through block table
2 = Move right through block table
N = Next screen
P = Previous screen
X = Create a new screen
D = Delete current screen
ENTER = Return to main menu



Sprite Images
-------------

Sprites are 16x16 pixel images which make up moving parts such as the player, player bullets, enemy craft, etc.  Sprites may have any number of frames.

Move around the grid with the cursor, fixing and deleting pixels with SPACE or 0.

X - insert sprite
D - delete sprite
C - clear sprite grid
M - copy sprite or tile to clipboard
K - copy sprite or tile from clipboard
N - next sprite
P - previous sprite
I - insert frame
R - remove frame
F - next frame



Sprite Positions
----------------

This allows you to position sprites in their start positions for each level using the cursor keys.  8 sprite types are available, and sprites can be set up as any of these, allowing you to position bonuses, enemy sprites, the player sprite's starting position or any other type of sprite you have set up.

N - next screen
P - previous screen
Q - move next sprite
I - change sprite image
T - change sprite type
D - delete current sprite from screen
X - add new sprite to screen



Objects
-------

Distinct from sprites, objects are static items which a sprite might pick up, or possibly drop.  Like sprites, they consist of 16x16 pixel images, although only have one frame.  These can be edited in much the same way as sprite images.

For each object you will need to define its position at the beginning of the game.  Unlike sprites, objects do not respawn every time the player enters a room, so they can be picked up in one room then dropped in another, making them ideal for arcade adventure games.  The starting screen is changed with Q and W keys.  A starting screen of 255 indicates that the object starts the game in the player's inventory.  Objects which are missing at the start of play, ie don't appear on any screen or in the player's inventory, should be assigned a starting screen of 254.  Press P to place an object in its designated position on its starting screen.

X - insert object
D - delete object
C - clear image grid
M - copy image or tile to clipboard
K - copy image or tile from clipboard
N - next object
L - last object
Q - change starting screen
W - change starting screen
P - position object on starting screen

Objects may be handled in the events code with GOT, GET, PUT and DETECTOBJ.  Additionally, the OBJ variable stores the result of the last DETECTOBJ command, although you can use it for other things as well, if required.  IF GOT n will be true if the player has object n in his inventory.  GET n will put object n in the player's inventory (regardless of wherever the object currently is), PUT n will drop an object at the current sprite position, and DETECTOBJ will check to see if the current sprite is touching an object, placing the result in the OBJ variable.  If no object is detected at the sprite position the value 255 will be returned.

For example, the following code will automatically pick up any object over which a sprite passes:

DETECTOBJ
IF OBJ = 255
ELSE
  GET OBJ
ENDIF

Because GET and PUT make no check to see if the object is already in the player's inventory, they can be used to place objects on screen or remove them more or less at will.  You may wish to have enemy sprites dropping bonuses, then remove them after a few seconds.  Just because you remove an object from the screen doesn't mean you have to award the points or bonus that the player would have gained by collecting it himself.



Map Layout
----------


AGD will allow sequential levels, but also has the ability to create explorer games where the player can explore a map.

The "map" of your game is arranged as a grid of 10 x 8 locations, all of which start off empty.  Empty locations appear as two hyphens "--", rooms appear as the screen numbers, eg "01" or "12".  As each room is designed in the screen designer it can be placed in this grid at a chosen location.  To move around the map simply use SCREENUP, SCREENDOWN, SCREENLEFT, SCREENRIGHT commands.  During the game it will not be possible for the player to move into an empty grid space.  commands such as NEXTLEVEL or LET SCREEN=9 will not alter the current map position, so are best used in games with sequential levels, unless you are confident of what you are doing.

The red cursor can be moved around the grid using the cursor keys, to change the room at a particular grid location move use keys '1' and '2'.  Rooms are displayed in the bottom two thirds of the screen as they are selected to make matters easier.

Your map will follow the rules of Euclidean geometry, but you can bend the rules to create a warped playfield should you desire.  Moving left from a room situated at the left edge of the map will cause the player to re-appear in the room placed at the right edge of the next row up, if one is placed there.  Similarly, moving right from a room at the right edge will take the player to the room  at the extreme left edge of the room one row below.  If you don't want this to happen you should construct walls on the relevant screens to form a physical barrier.  It is also possible to re-use a room, that is to make it appear more than once in your map.

Moving from one screen to another will not alter the player sprite's coordinates, so these should be set manually at the same time as the SCREENLEFT, SCREENRIGHT etc. is performed.  Any player sprites set up for a screen will only be used for the very first screen, or to spawn a new player sprite should he die on that screen.  Should the player die on a screen where he has no default position he will not be respawned.

Press 'X' to declare a grid location as the point at which the player is to begin the game.

1 = Select previous room from list
2 = Select next room from list
X = Select room where player first starts the game
ENTER = Return to main menu



Jump Table
----------

If your game makes use of gravity, you may want to edit the jump table.  This allows you to edit the steepness of jumps and/or falls, allowing you to determine how high sprites can jump, or how quickly they descend when they fall through gaps in the floor.

The jump table is separated into a series of individual steps, and you can change the distance between these steps with the cursor keys.  The red column represents the step you are currently editing.  When you are happy with your jump table, press ENTER to return to the main menu.



Sound
-----

H - Hear present sound
N - Next sound
P - Previous sound
X - Create new sound
D - Delete sound

Move around the values with the cursor keys, increasing and decreasing them with 1 and 2.  SPACE or 0 will toggle noise or tone off.

To play a sound in your game, use the SOUND command in the relevant event.



Save Game
---------

Prompts for a filename, then saves your game as a code file which can be loaded in later and edited, or used as a stand-alone executable.  If you wish to run your game independently of the utility you will need to record a BASIC loader program onto the tape first - if you are using emulation this could prove to be tricky.  the simplest program to do this would be:

10 CLEAR 34599: LOAD ""CODE : RANDOMIZE USR 35800

Of course, you might want to set up a few other things first, such as the BORDER, PAPER and INK colours, plus a title page and maybe even a border around the status panel.  If this is all too complicated, you may wish to take advantage of Intro Maker, another free utility by the same author, which creates the BASIC loader and introduction screen for you automatically.



Load Game
---------


Loads a new game from tape.  If you are using an emulator, you will have to operate the tape browser yourself.  Emulators with no tape browser, and those which automatically load inserted tapes are not recommended for AGD.  AGD will only load code files which have been created with the utility.



Test Game
---------

Allows you to test your creation.  Press ENTER at any point to return to the editor.



Messages
--------

This is where you can define the text messages your game will use.  Press ENTER at any point to return to the main menu.

N = Next message
P = Previous message
X = Create new message
D = Delete message




Events
------

This is the part where you get to have a say about the game logic, and can change the way it works in a variety of different ways.  While the editor and compiler are not going to rival a proper language like BASIC, AGD does provide a very limited number of statements, functions and variables which should enable any number of fundamentally different arcade games to be created.  Think of it as an arcade version of GAC - you may need to be very inventive about how you implement the features you want, but then that is half the fun.

To modify the events, use cursor up/down to select the event, then press space or 0.  Once selected, the code editor allows you to edit the code for that particular event.  Symbol shift and A returns to the event selection screen.  The editor will quickly run over your code, and report back if it does not understand any of it.

Aside from events which occur at certain times in the game, there are events associated with 8 sprite types.  These are the events which control the movement and logic of each type of sprite.  Sprite type 0 is usually reserved for the player's sprite, so this code should test for keys and move the sprite around accordingly.  The rest are all yours to do with as you wish.  You could choose to make sprite types 1 and 2 different alien nasties with different movement patterns, and perhaps use sprite type 3 for bonus sprites which the player picks up.

Functions can only be used after an IF.  

IF
Test.  If the following condition is true the code up to the next ENDIF statement is executed.  IF can be used with a function, or to test variables or sprite parameters against each other, or against specific numeric values.  

ENDIF
Marks the end of the conditional code.

LET
As in BASIC, this allows you to assign a value to a variable or sprite parameter.  The value assigned can be a number, or another variable or sprite parameter.

KEY
Function.  Expects a single numeric argument and condition is true if the key is pressed.

CANGOUP, CANGODOWN, CANGOLEFT, CANGORIGHT
Functions.  Condition is true if the current sprite can move up/down/left/right.

LADDERUP, LADDERDOWN
Functions.  Condition is true if the current sprite can go up/down a ladder.

X, Y
Sprite parameters.  These are the coordinates of the current sprite.

A, B, C, D, E, F, G, H
Global variables.  These hold 8-bit values.

SCREEN, LIVES
Global variables.  These contain the current screen number and the lives remaining.

TYPE
Sprite parameter.  This is the type of sprite being processed.  Best used in conjunction with the IMAGE parameter, setting this parameter will completely change the sprite's behaviour - handy for turning a nasty into a bonus, or making a sprite stop and explode before killing it.  There is no reason why you couldn't change a sprite to type zero and put it under the player's control, or change the player's sprite type to something else with a slightly different set of controls.  So long as the new sprite type has appropriate code set up in the relevant event, there's no limit to what you could do.  If you haven't set up any code for the sprite type your sprite will just sit there - which may be okay if that's what you want.

IMAGE, FRAME
Sprite parameters.  These are the sprite and frame numbers shown in the sprite editor.  You can change the sprite according to whichever direction the player is facing, or perhaps you might want to give the player a choice of vehicles to control.  Setting a frame number beyond the limit of the sprite will result in a different sprite image being displayed, so use FRAME with caution.

DIRECTION, PARAMA, PARAMB
Sprite parameters.  You can use these as you see fit, perhaps to indicate the direction in which a particular sprite is moving, or the particular phase it is going through.  Invaluable for any form of enemy AI.

ANIMATE
Command.  Animates the present sprite, automatically cycling through the frames.

NEXTLEVEL, RESTART
Commands.  Move to next level, and restart current level respectively.

SPRITEUP, SPRITEDOWN, SPRITELEFT, SPRITERIGHT
Commands.  Move the current sprite accordingly.  No check is made for blocks in the way, or out-of-screen conditions, so you will have to do that yourself with functions such as CANGOLEFT or LADDERUP.

SPAWN
Command.  Expects 2 parameters for sprite type and image.  This spawns a new sprite with the specified type and image at the current sprites's position.  The new sprite is created with FRAME, DIRECTION, PARAMA and PARAMB all set to zero.  The current sprite is unaffected.

REMOVE
Command.  Removes the present sprite from the table.  Useful for destroying enemies or picking up objects.

DIGUP, DIGDOWN, DIGLEFT, DIGRIGHT
Commands.  These remove any fodder blocks above, below, or to the left or right of the current sprite.  The attributes for all removed blocks will be set to the same colours as those used for block zero.  Any other blocks are unaffected.

COLLISION
Function.  Requires one numeric argument to specify the sprite type.  Condition is true if the current sprite is in collision with another sprite of the type specified.

TOGGLE
Command.  Should only be used immediately following a successful COLLISION check.  Toggles between the sprite you were processing (the primary sprite), and the secondary one with which it has just collided.  Any code written after the first toggle command will refer to the secondary sprite.  Use TOGGLE again to switch back to the primary sprite when you have finished the code for the secondary sprite.  You should not use COLLISION again until you have toggled back to the original primary sprite, or AGD will lose track of that sprite.

SHOWSCORE
Command.  Shows the score at the current cursor position.  Should be immediately preceded by instructions setting up the line and column position for the cursor.

SCORE
Command.  Expects to be followed by a number to add to the score.  SCORE 100 will add 100 points to the player's total.  Values 0 to 255 are valid.

SOUND
Command.  Starts a sound effect.  Expects a single parameter for the sound number to play.

CLS
Command.  Clears the screen.

BORDER
Command.  Expects an argument from 0 to 7 inclusive.  Sets the border colour.

COLOUR
Command.  Expects an argument.  Sets the permanent display attributes.  Format is 128 * FLASH + 64 * BRIGHT + 8 * PAPER + INK.  Can be used prior to displaying text or clearing the screen.

DELAY
Command.  Expects an argument.  Pauses for the duration specified.

MESSAGE
Command.  Expects an argument for the number of the message to display.

KILL
Command.  Initiates the kill player event and decrements the life counter.  You should set up the lives counter in the initialisation event using something like LET LIVES = 3.

LINE, COLUMN
Variables.  These determine the position at which the score or message will be displayed.  They are temporary and change every time a sprite is displayed, so always use them immediately before a MESSAGE or SHOWSCORE command.

GETRANDOM
Function.  Generates a random number between zero and the argument, and places it in the RND variable.  GETRANDOM 100 will generate a number from 0 to 99, GETRANDOM 2 will generate a zero or 1.

RND
Variable.  The last random number generated by GETRANDOM.

ADD, SUBTRACT
Commands.  Add or subtract to or from a sprite parameter or variable, eg. ADD 1 TO A or SUBTRACT 5 FROM B.

SCREENUP, SCREENDOWN, SCREENRIGHT, SCREENLEFT
Commands.  Move up, down, left or right one screen if possible.

DEADLY
Function.  Condition is true if the current sprite is in contact with a deadly block.

WAITKEY
Command.  Waits for a keypress.

JUMP
Command.  The current sprite will jump, provided it is not already in mid-air and there are no walls in the way.  As you would expect, any sprite can be made to jump, not just those under the direct control of the player.

FALL
Command.  Provided the sprite is not already falling or jumping, this checks to see if the sprite is standing on top of solid ground.  If not, it will start to fall, using the descending half of the jump table (your game will automatically find this point, even if you have modified the jump table).  FALL is useful if a sprite type is subject to gravity, eg platform games.

GOT
Function.  Used in IF statements and expects a single argument.  The expression is true if the specified object is owned by the player.  The argument can be a variable if required, so IF GOT 1 is valid, as is IF GOT A.  You could even use a sprite parameter as an argument if you wish.

GET
Command.  Expects a parameter specifying the object to get.  Places the specified object in the player's inventory, regardless of where it is.  The object could be on the current screen, another screen, or just missing.  It is up to you to decide when the player can get a particular object.  You may want to use DETECTOBJECT to determine when a sprite is touching an object first.

PUT
Command.  Requires an argument specifying the object number.  The object is dropped onto the screen at the current sprite's position, unless it is already on the current screen.  Argument can be numeric, a variable or sprite parameter.

DETECTOBJ
Command.  Detects objects touched by the current sprite, and places the result in the OBJ variable.  If the sprite is touching more than one object, only the object with the lowest number is detected.  If no object is detected, OBJ will be set to 255.

OBJ
Variable.  The last object number detected by DETECTOBJ.



Technical information
---------------------

Games created with the utility are stand-alone, and should work independently of the editor itself.  AGD does not change the interrupt mode, so you are free to set up your own interrupts, to play music, for example.  However, you should not disable the interrupts.  If you wish to set up your own interrupts using IM2, make sure your service routine increments the byte at memory location 23672 every frame, or your game will hang.  AGD does not change the value of the IY register, although IX is used throughout, mostly as a sprite pointer.

Games occupy memory from 35800 upwards, and this is the area that is saved by the utility.  Below this lies the code for the editor.  At the very top of RAM, the last 768 bytes from 64768 to 65535 are used as a dummy collision map area to distinguish between different types of blocks - walls, ladders, empty space and so on.  No buffer is required for screen data decompression, since these are expanded on-the-fly by the routine which draws the screen.
